Top 10k strings from Programmierung der Z80 (19xx)(-)(de).tzx
in <root> / bin / z80 / software / Sinclair Spectrum Collection TOSEC.exe / Sinclair ZX Spectrum - Utilities & Educational / Sinclair ZX Spectrum - Utilities & Educational - [TZX] (TOSEC-v2007-01-01) /
Back to the directory listing
4 "1) den Inhalt der Adresse hl"," 3 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 3 a$="Seite "+ 3 a$=" Druecken Sie jetzt bitte eine beliebige Taste...": 3 ;"________________________________": 3 0 + 0 = 0"," 3 2 drck=druck: 2 d$="00111100": 2 d$="00011110": 2 a$=a$+o$(n)+" ": 2 a$="ld a , ( hl )": 2 a$="Moechten Sie hier auch Druckerauszuege von jeder Seite ? ( ja / nein )": 2 a$="LD c , l": 2 a$="LD bc , 240": 2 a$="LD b , h": 2 a$="Druecken Sie jetzt eine Taste ..." 2 a$="Befehl": 2 a$="= Register/Zahl": 2 a$="= Akkumulator": 2 a$="= Akku nachher": 2 a$="237 , "+ 2 Druecken Sie jetzt eine Taste ... 2 1 + 1 = 1" 2 1 + 0 = 1"," 2 0 + 1 = 1"," 2 "Befehl"," 2 "1) den Inhalt vom Port c zum Byte ( hl )"," 2 "1) Akku mit dem Byte ( hl ) ver-"," 1 zur Adresse de bringen","2) de = de - 1","3) hl = hl - 1","4) bc = bc - 1": 1 zur Adresse de bringen","2) de = de - 1","3) hl = hl - 1","4) bc = bc - 1","5) solange zu Punkt 1) springen,"," 1 zur Adresse de bringen","2) de = de + 1","3) hl = hl + 1","4) bc = bc - 1","5) solange zu"," 1 re)+". Gleichzeitig legt er die Return-Adresse auf den Stack. Ein ret-Befehl nimmt diese dann vom Stapel und springt zurueck.": 1 q$=q$+i$(m): 1 q$="(iy+N)" 1 p$=p$+i$(n) 1 p$="(iy+N)" 1 p$="(iy)") 1 k$="6831": 1 k$="1011010": 1 k$(n)+" x "+ 1 gleichen (Zero-Flag)","2) hl = hl - 1","3) bc = bc - 1": 1 gleichen (Zero-Flag)","2) hl = hl + 1","3) bc = bc - 1": 1 druck=drck: 1 druck=drck 1 d$=d$+i$(n): 1 d$="popep m " 1 d$="bcdehlfa" 1 d$="10011011": 1 bringen","2) b = b - 1","3) hl = hl - 1": 1 bringen","2) b = b - 1","3) hl = hl - 1","4) zum Pkt. 1) springen, bis b = 0": 1 bringen","2) b = b - 1","3) hl = hl + 1": 1 bis bc = 0" 1 b$="zieht, wenn der Inhalt des Akkus > 159 ist, 160 ab. In beiden Faellen wird 6 hinzuaddiert.": 1 b$="zieht vom b-Register 1 ab und erhoeht den Programmzaehler nur um DIS, wenn b < > 0 ist.": 1 b$="zieht den Akku von 256 ab a = 256 - a": 1 b$="zieht "+p$+" vom Akkumulator ab .": 1 b$="verschiebt das Register "+p$+" um ein Bit nach rechts, wobei der Inhalt des Carry in die Luecke, das herausgerollte Bit ins Carry rutscht.": 1 b$="verschiebt das Register "+p$+" um ein Bit nach links, wobei der Inhalt des Carry in die Luecke, das herausgerollte Bit ins Carry rutscht.": 1 b$="verschiebt das Register "+p$+" nach rechts. Das herausgerollte Bit rutscht sowohl in die Luecke, als auch in das Carry-Flag.": 1 b$="verschiebt das Register "+p$+" nach rechts, wobei eine Null in die Luecke wandert. Das herausgerollte Bit wandert ins Carry.": 1 b$="verschiebt das Register "+p$+" nach rechts, wobei das herausgerollte Bit in das Carry wandert. In die Luecke rutscht dasselbe Bit, was sich vorher dort befand.": 1 b$="verschiebt das Register "+p$+" nach links. Das herausgerollte Bit rutscht sowohl in die Luecke, als auch in das Carry-Flag.": 1 b$="verschiebt das Register "+p$+" nach links, wobei eine Null in dei Luecke rutscht. Das herausgerollte Bit wandert ins Carry.": 1 b$="vergleicht das Byte "+p$+" mit dem Inhalt des Akkus. Trifft der Vergleich zu, so wird das Zero-Flag = 1 gesetzt.": 1 b$="uebergibt den Inhalt des Registers "+q$+" an das Port "+p$(2 1 b$="tut ueberhauptnichts.": 1 b$="tauscht die Inhalte der Registersaetze untereinander aus.": 1 b$="tauscht die ""Digits"" der Bytes a und ( hl ) wie oben gezeigt wird, aus.": 1 b$="tauscht "+q$+" und "+p$+" miteinander aus.": 1 b$="subtrahiert vom Register "+w$+" sowohl das Carry-Flag, als auch das Register "+q$+" .": 1 b$="springt zum Unterprogramm mit der Adresse NN "+(", wenn die Bedingung "+p$+" efuellt ist" 1 b$="setzt das "+w$+" . Bit des Registers "+q$+" = 1 .": 1 b$="setzt Carry-Flag = 1 .": 1 b$="loescht das "+w$+" . Bit des Registers "+q$+" .": 1 b$="liest das Port "+q$(2 1 b$="liest das "+w$+" . Bit des Registers "+q$+" . Das Ergebnis wandert in das Zero-Flag .": 1 b$="laedt "+q$+" in den Stackpointer hinein.": 1 b$="laedt "+q$+" in "+p$+" hinein.": 1 b$="kehrt vom Unterprogramm zurueck ins Hauptprogramm.": 1 b$="kehrt nur ins Hauptprogramm zurueck, wenn die Bedingung "+p$+" erfuellt ist.": 1 b$="invertiert den Inhalt des Akkus vollstaendig a = 255 - a": 1 b$="invertiert Carry-Flag.": 1 b$="holt die obersten zwei Bytes vom Stack und gibt sie in das Registerpaar "+p$+" . Der Stackpointer sp wird um 2 erhoeht.": 1 b$="geschrieben 1 b$="erniedrigt "+p$+" um 1 .": 1 b$="erhoeht "+p$+" um 1 .": 1 b$="entspricht einem call "+p$+" .": 1 b$="bringt das Registerpaar "+p$+" an die Adresse des Stackpointers sp und zieht von sp 2 ab.": 1 b$="addiert zum Registerpaar "+w$+" das Paar "+q$+" hinzu .": 1 b$="addiert zum Register "+w$+" sowohl das Carry-Flag, als auch das Register "+q$+" .": 1 b$="addiert zum Akkumulator das Byte "+q$+" .": 1 b$="Springt zur Adresse "+q$+" , wenn die Bedingung "+p$+" erfuellt ist .": 1 b$="Springt zur Adresse "+p$+" .": 1 b$="Erhoeht den Programmzaehler um DIS"+(" , wenn die Bedingung "+p$+" zutrifft." 1 b$="= bitweise UND - Funktion mit dem Operanden "+p$+" . Ergebnis in Akku, wenn Null, Zero-Flag = 1": 1 b$="= bitweise ODER - Funktion mit dem Operanden "+p$+" . Ergebnis in Akku, wenn Null, Zero-Flag = 1.": 1 b$="= bitweise Exclusive ODER - Funktion mit dem Operanden "+p$+" . Ergebnis in Akku, wenn Null, Zero-Flag = 1": 1 b$="11010111": 1 b$=" 1 a$=a$+b$(n)+" ": 1 a$=a$+"Dazu folgendes Programm :": 1 a$=a$+" Aber Doppelregister setzen das Zero-Flag schon auf eins, wenn eines der beiden Einzelregister bei Null angelangt ist. Also muessen wir mit OR arbeiten, wie folgendes Beispiel zeigt :": 1 a$="und das Register- Bit = 1 sind.": 1 a$="umwandeln, verwandelt er sich in den Befehl": 1 a$="ueberhauptnichts.": 1 a$="stop = Ende der Eingabe": 1 a$="set 7 , a .": 1 a$="set 0 , a": 1 a$="schreiben, sondern man muss": 1 a$="scf bedeutet ""set carry-flag"" und setzt das Carry-Flag = 1.": 1 a$="rst "+ 1 a$="out ( 254 ) , a": 1 a$="out ( c ) , "+e$: 1 a$="out ( N ) , a": 1 a$="oder das Register- Bit = 1 ist.": 1 a$="nur dann zur Adresse NN, wenn das Z-Flag ungleich 1 ist.": 1 a$="nur dann zur Adresse NN , wenn das Z-Flag 1 ist.": 1 a$="niederwertiges Byte": 1 a$="nach Aufruf dieses Programmes mit PRINT USR 40000 schreibt der Computer die Zahl 240 auf den Bildschirm.": 1 a$="mit Uebertrag einer 1 auf die naechste": 1 a$="ld a , ( ix + N )": 1 a$="koennen dann anhand des Carry-Flags Entscheidungen treffen.": 1 a$="jr z , DIS": 1 a$="jr nz , DIS": 1 a$="jr DIS": 1 a$="jp z , NN": 1 a$="jp nz , NN": 1 a$="in "+e$+" , ( c )": 1 a$="hoeherwertiges Byte": 1 a$="gesetzt werden.": 1 a$="eingeben, da fuer die Uebertragung von Registerpaaren keine Befehle vorgesehen sind.": 1 a$="djnz DIS": 1 a$="dec b : jr nz , DIS": 1 a$="das bewirkt der Befehl rr ": 1 a$="dafuer aber sogenannte ""Flags"" , die erkennen, ob eine Bedingung wahr ist (1) oder falsch (0). Es gibt fuer solche Zwecke 6 Flags, die als sechs Bits in dem F - Register stehen.": 1 a$="ccf bedeutet ""complement carry-flag"" und negiert das Carry-Flag.": 1 a$="benutzen. Beachten Sie, dass das Flag-Register f zusammen mit dem Akku abgespeichert wird.": 1 a$="bedeutet": 1 a$="b) ein Einzelregister durch inc oder dec auf Null gekommen ist. Das Zero-Flag ( kurz Z-Flag genannt ), ist bereits in vielen Befehlen integriert." 1 a$="auf dem ZX-Spectrum 48K": 1 a$="akku ( hl )"(1 1 a$="a) der Akkumulator Null ist , oder": 1 a$="a' , f' , b' , c' , d' , e' , h' und l'": 1 a$="________________________________": 1 a$="Zum Verdoppeln, sowie Halbieren eines Registerinhaltes, wobei das Carry-Flag beim Verdoppeln anzeigt, ob ein Ueberlauf stattfand, und beim Halbieren, ob die Zahl nicht mehr durch 2 teilbar war.": 1 a$="Zum Erzeugen eines Tons in dieser Art, sendet man zuerst eine Zahl zwischen 0 und 7 ( bedingt auch die Farbe ) zum Port. Nach einer bestimmten Zeit schickt man eine Zahl zwischen 248 und 255 ( 248 + Farbe ) zum Port.": 1 a$="Zum Beispiel springt der Befehl": 1 a$="Zuerst wird die Bitreihe verschoben. Das rechteste Bit rutscht ins Carry-Flag und gleichzeitig in die Luecke auf der linken Seite. Das bedeutet, dass nach achtmaligem Ausfuehren dieser Funktion das Byte wie vorher vorliegt.": 1 a$="Zuerst stellen wir folgende Tabelle auf :": 1 a$="Zuerst befassen wir uns mit den Befehlen set , res und bit der 203er-Gruppe. Um sie zu verstehen, muessen wir uns wieder ein Byte als 8 Bit vorstellen. Wenn der Inhalt des Akkus z.B. 60 ist, so sieht das so aus :": 1 a$="Zeile muss im c - Register, Spalte im b - Register stehen. Ergebnis steht dann wieder im c-Register": 1 a$="Zahlenausdruck an der laufenden PRINT-Position : Startadresse = 6683": 1 a$="Zahl muss vorher im bc-Registerpaar stehen.": 1 a$="Y - Koordinate muss vorher im b - Register stehen, X - Koordinate im c - Register": 1 a$="Wuerden wir jetzt das Byte nocheinmal zusammenrechnen, so kaemen wir auf 30 . Wie Sie sehen, hat sich der Inhalt des Akkus durch den Befehl srl halbiert. Beachten Sie, dass das Carry-Flag in diesem Falle Null geworden ist. Die Befehle": 1 a$="Wollen wir dagegen das Bit Nr. 7 (ganz links) setzen, so schreiben wir": 1 a$="Wollen Sie jede Seite auf dem Drucker ausgedruckt haben ( ja / nein ) ?": 1 a$="Wir wollen uns dafuer ein Programm ansehen, was den SCREEN des Spectrum invertiert. Der Bildspeicher faengt ab Adresse 16384 an und hat die Laenge von 6144 Bytes. Also muessen wir eine Schleife haben, die von 6144 auf 0 zurueckzaehlt und dabei das hl-Register (anfangs 16384) immer um 1 erhoeht." 1 a$="Wir wollen uns aber direkt mit der Hauptsprache der Z80 befassen.": 1 a$="Wir wollen dazu ein kleines Programm betrachten :": 1 a$="Wir wollen auf der naechsten Seite ein paar Anwendungsprogramme fuer die Operation OR in Verbindung mit cpl sehen.": 1 a$="Wir hatten schon die Befehle adc und sbc kurz besprochen, als wir ueber die 237er-Gruppe redeten. Der Befehl adc a , b z.B. addiert zum Akku zuerst das b-Register und zusaetzlich den Inhalt des Carry-Flags. Das bedeutet, wenn a = 10 ist, und b = 5 , so erhalten wir, wenn das Carry-Flag Null ist, als Ergebnis 15." 1 a$="Wir haben das Programm also folgendermassen analysiert :": 1 a$="Will man zwei Adressen weiter weg springen, muss DIS = 1 sein, usw. Sehen Sie folgende Beispiele :" 1 a$="Will man z.B. die zahlen 12 und 14 multiplizieren, stellt man eine b-Schleife auf, die von 12 bis Null rueckwarts zaehlt, und erhoeht in dieser Schleife den Akku, der anfangs Null ist, um 14. Am Ende dieser Schleife traegt der Akku das Ergebnis 12 x 14 = 168 .": 1 a$="Will man dagegen nach oben (also rueckwaerts) springen, so muss bei einem Sprung DIS = 253 sein. Bei zwei Spruengen rueckwaerts muss DIS = 252 sein, usw .": 1 a$="Wie wir wissen, benoetigt ein call NN - Befehl 3 Bytes. Das ist fuer Z80-Verhaeltnisse relativ viel. Um etwas Speicherplatz sparen zu koennen, wurde der RST - Befehl ( Restart ) eingefuehrt. Es gibt acht verschiedene RST-Befehle, die genau die selbe Wirkung wie call-Befehle haetten. Es gibt :": 1 a$="Wie wir sehen, bedeutet eine Stelle dieser Binaerzahl ein Bit. Nun, der Befehl set kann einzelne Bits setzen. In gleicher Weise kann der Befehl res Bits zuruecksetzen. Dazu ist der Name des Einzelregisters, sowie die Nummer des Bits ( 7 bis 0 ) notwendig. Da es sich hier um den Akku handelt, kann das Bit Nr. 0 (ganz rechts) mit dem Befehl": 1 a$="Wie wir hier sehr gut sehen koennen, befindet sich das Programm in einer Endlosschleife, d.h., der ret-Befehl wird niemals erreicht.": 1 a$="Wie wir hier sehen koennen, wartet die b-Schleife 200 Mikrocyclen ab. Der Index der hl-Schleife bestimmt die Tonlaenge. Bitte variieren Sie den Index der b-Schleife, um unterschiedliche Tonlhoehen zu bekommen.": 1 a$="Wie wir am JP-Befehl sehen koennen, benoetigt er eine Zieladresse, die immer feststehen muss. Kurzprogramme mit diesem Befehl lassen sich nicht verschieben und ausserdem kostet es ziemlich viel Speicherplatz, wenn man auch nur einen kurzen Sprung ausueben will ( 3 Bytes ).": 1 a$="Wie man hier sehr gut sehen kann, veranlasst die b-Schleife hier, dass a 150-mal um 1 erhoeht wird. Am Ende dieses Programmes ist a = 150 und b = 0. Auf diese Art ist es moeglich, Multiplikationsprogramme zu schreiben.": 1 a$="Wie bereits erwaehnt wurde, kann man nur mit dem a-Register (Akku) rechnen. Wenn wir also z.B. die Zahlen 100 und 80 zusammenaddieren wollen, benutzen wir den Befehl add . Er addiert zum Inhalt des Akkus entweder eines der Register b, c, d, e, h oder l hinzu, oder eine beliebige Zahl mit dem Befehl add a , N (wobei N wieder eine Zahl zwischen 0 und 255 sein muss ) ." 1 a$="Wie arbeitet man mit dem Befehl rst 16 ?": 1 a$="Wie Sie wissen, benutzt die Z80 die Register a, f, b, c, d, e, h und l . Nun, neben diesem Registersatz kennt die Z80 einen weiteren derartigen Registersatz mit den Registern": 1 a$="Wie Sie wissen, bedeutet die Klammer ""den Inhalt"" einer Adresse oder Variablen. Da man mit dem Befehl ld a , ( NN ) das Byte ab Adresse NN in den Akku laden kann, kann man z.B. mit dem Befehl ld hl , ( NN ) das l-Register mit dem Byte an Adresse NN, sowie das h-Register mit dem Byte, das an Adresse NN+1 steht, laden.": 1 a$="Wie Sie wissen duerften, kennt ein Computer nur die Zustaende 1 und 0 . Das sind in Wirklichkeit die einzigen Ziffern, die er kennt, im Gegensatz zu unseren zehn Ziffern.": 1 a$="Wie Sie sicher bereits gemerkt haben sollten, ist der BASIC-Befehl USR dasselbe wie call, auch hier muss am Ende des aufgerufenen Programmes ein ret stehen. ": 1 a$="Wie Sie sehen, bedeutet jede Stelle ein Vielfaches von Zehn. Also setzt sich z.B. die Zahl 1386 folgendermassen zusammen :": 1 a$="Wichtig sind diese Befehle zum Bestimmen vom Vorzeichen eines Ergebnisses einer Summe oder Subtraktion.": 1 a$="Wichtig dabei ist, dass vor jedem rst-Befehl alle Register, die benutzt werden, mit push gerettet werden." 1 a$="Wichtig bei call ist, dass am Ende des aufgerufenen Unterprogrammes ein ret stehen muss (wie RETURN in BASIC).": 1 a$="Wenn z.B. das hoeherwertige Byte auf 1 steht, so bedeutet das nicht 1 , sondern 1 x 256 :": 1 a$="Wenn wir z.B. den Befehl": 1 a$="Wenn wir uns aber eine Binaerzahl ansehen, bedeutet jede Ziffernstelle ein Vielfaches von zwei, also EINER, ZWEIER, VIERER, ACHTER, usw.": 1 a$="Wenn wir jetzt auch dieses Programm analysieren wollen, so stehen wir vor einem Problem. Der Befehl LD bc , 240 besteht nicht nur aus einer Zahl, sondern aus dreien. Der Code dieses Befehles ist 1 . Wenn wir im Anhang C des Handbuches suchen, finden wir den Befehl LD bc , NN .": 1 a$="Wenn wir dann die Binaerzahl 1011010 in eine Dezimalzahl umrechnen wollen, so muessen wir wie folgt vorgehen :": 1 a$="Wenn wir dann PRINT USR 40000 eingeben, wird ebenfalls wie im vorigen Beispiel die Zahl 240 auf den Bildschirm geschrieben.": 1 a$="Wenn wir also den Akku AND ein anderes Byte oder Register verknuepfen wollen, so muessen wir, um das Ergebnis zu erhalten, Bit fuer Bit verknuepfen. Das Ergebnis wandert wieder in den Akku.": 1 a$="Wenn wir aber ein Einzel- oder Doppelregister nur um 1 vergroessern oder verringern wollen, stehen uns die Befehle inc bzw. dec zur Verfuegung. Also zaehlt der Befehl inc d zu dem d-Register 1 hinzu, waehrend dec a vom Akku 1 abzieht. Dasselbe gilt fuer die Registerpaare bc, de und hl ." 1 a$="Wenn sich die Z80 einmal in so einer Endlosschleife befindet, d.h., wenn nicht mehr zum BASIC zurueckgesprungen werden kann, muss man den Netzstecker ziehen. Um soetwas zu umgehen, nimmt man im BASIC IF-Befehle, die erkennen, ob eine bestimmte Bedingung erfuellt ist, oder nicht. In der Z80-Maschinensprache gibt es zwar keine IF-Befehle,": 1 a$="Wenn Spruenglaengen groesser als +129 oder kleiner als -126 notwendig sind, muessen Sie halt auf Jp zurueckgreifen.": 1 a$="Wenn Sie irgendeinen ix, iy - Befehl im Anhang C des Handbuches suchen, dann finden Sie lediglich zwei Codes, naemlich": 1 a$="Wenn Sie im Anhang C des Handbuches nachschlagen, dann finden Sie Befehle wie": 1 a$="Wenn Sie bei dem Code 203 einen Befehl suchen, finden Sie nichts.": 1 a$="Weitere Befehle in dieser Gruppe sind adc (add with carry) und sbc (subtract with carry). Adc und Sbc tun genau dasselbe wie add und sub, sie addieren oder subtrahieren jeweils noch das Carry-Flag mit. Da es z.B. keinen sub hl , de -Befehl gibt, muessen Sie den Befehl sbc hl , de dafuer verwenden.Solange das Carry-Flag nicht 1 ist, aendert das am Ergebnis nichts.": 1 a$="Was als Dezimalzahl 60 bedeutet. Wenn wir das ganze Byte um ein Bit nach rechts verschieben wollten, wuerden wir den Befehl srl verwenden. Nach dem Rollvorgang entsteht auf der linken Seite eine Luecke. In diese Luecke rutscht eine Null. Da auf der rechten Seite ein Bit verschwindet, rutscht dieses Bit in das Carry-Flag, wo es von den Bedingungsbefehlen call, jr, jp und ret abgefragt werden kann.": 1 a$="W e i t e r e F l a g s": 1 a$="W e i t e r e B e f e h l e :": 1 a$="Vor dem Aufruf muss im de-Registerpaar die Startadresse des zu druckenden Textes stehen, im bc-Register die Laenge des Textes.": 1 a$="Vor dem Aufruf muss im de-Register die Tonlaenge, im hl-Register die Tonhoehe stehen.": 1 a$="Verwenden Sie bitte den Anhang C des BASIC-Handbuches zum nachschlagen der Codes.": 1 a$="Unsere eigenen Maschinencode-Routinen legen wir am Besten im Bereich von 30000 bis 65000 ab. Wichtig ist, dass die Systemvariable RAMTOP unterhalb dieser Routinen liegen muss. Dazu geben wir hier den BASIC-Befehl CLEAR 39999 ein, um auch noch genug Platz fur BASIC-Programme zu lassen." 1 a$="Und wenn Sie 2 oder mehrere Binaerzahlen addieren wollen, so gehen Sie auch hier genauso wie im Dezimalsystem vor, ausser, dass Sie hier folgende Regeln beachten muessen :": 1 a$="Und um z.B. dem Registerpaar hl den Wert des Registerpaares bc zu geben, schreiben Sie :": 1 a$="Und die Befehle inc ( hl ) und dec ( hl ) erhoehen also nicht das hl-Register um eins, sondern den Inhalt der Adresse hl .": 1 a$="Und der Befehl cpd macht dies :": 1 a$="Um diese beiden Bytes nun als eine gesamte Zahl zu benutzen, muessen wir wie folgt rechnen :": 1 a$="Um diese Zahl errechnen zu koennen, muessen wir die beiden Bytes, aus denen der jr DIS -Befehl besteht, getrennt betrachten. Das erste Byte ist der Befehl selbst. Das zweite Byte ist die Zahl DIS . Nun kommt es vor allem auf die Adresse dieser Zahl DIS an. Will man eine Adresse weiter nach unten springen, muss DIS = 0 sein.": 1 a$="Um diese Befehle zu erhalten, stellt man die Zahl 203 voran, gefolgt von dem normalen Code. Also bedeutet dann der Code mit der Nummer 1 nicht mehr ld bc,NN , sondern rlc c (was das bedeutet, erfahren Sie spaeter) . Ebenso gibt es eine 237er-Gruppe, deren Befehlen eine 237 vorangestellt werden muss.": 1 a$="Um den Wert von einem Registerpaar zu einem anderen zu uebertragen, koennen wir nicht einfach": 1 a$="Um das Problem zu umgehen, steht der Z80-CPU der Stapel zur Verfuegung. Um die Variablen vor einem Unterprogrammaufruf zwischenzuspeichern, legt man sie mit dem push - Befehl auf den Stapel ab. Hinterher holt man sie mit pop wieder vom Stapel.": 1 a$="Um Bits zuruecksusetzten, verwenden wir den Befehl res (reset). Er wird genauso angewandt wie set . Diese beiden Befehle koennen auf alle Einzelregister angewandt werden .": 1 a$="Trotz dieser Barrieren ist es moeglich, selbst komplizierte Programme masszuschneidern. Manchmal ist mehr als nur ein Anlauf noetig, um ein MC-Programm fertigzustellen, doch man wird mit einer Spitzengeschwindigkeit bedankt." 1 a$="Stoppen Sie auch jetzt das Tonband und lassen es in dieser Stellung stehen !": 1 a$="Stoppen Sie auch das Tonband !": 1 a$="Stelle.": 1 a$="Starten Sie das Tonband !": 1 a$="So, genug des Lehrmaterials. Wenn Sie jetzt noch nicht alles verstanden haben sollten, nicht traurig sein, sondern von vorne laufen lassen ! ! !": 1 a$="So auch in Maschinencode. Man laedt dazu die Kanalnummer in den Akku und ruft dann die ROM-Routine ab 5633 auf.": 1 a$="Sie stiegen soeben aus BASIC aus und in Maschinensprache ein ! Beachten Sie, dass es nicht einfach sein wird, das alles zu begreifen, da die Programmierung in der Z80-Maschinensprache im Vergleich zum BASIC unkomfortabel und computerorientiert ist." 1 a$="Sie koennen neben dem Akkumulator auch das hl-Register sehr oft fuer mathematische Operationen verwenden. Es gibt z.B. folgende 2-Byte-Additionsbefehle :": 1 a$="Sie kennen die BASIC-Befehle GOTO und GOSUB . Natuerlich gibt es Aequivalente in der Maschinensprache. Diese heissen JP (Jump) und call . Ihnen folgt jeweils eine 2-Byte Adresse, die anzeigt, wohin gesprungen werden soll.": 1 a$="Sie duerfen hier den Luxus von Kommazahlen, trigonometrischen Funktionen, Zufallszahlen- generator und Graphik vergessen.Stattdessen ist es hier moeglich, ungehindert schnelle Programme zu schreiben.Aber auch das ist oft nicht leicht, denn der Computer kennt Befehle nur in Form von Zahlen." 1 a$="Sehen wir uns eine normale Dezimalzahl an, so stellen wir fest, das wir mit der rechtesten Ziffer die EINER-Stelle haben. Die naechste ist die ZEHNER, die uebernaechste die HUNDERTER, usw.": 1 a$="Sehen wir uns dazu dieses kurze Programm an :": 1 a$="Sehen wir uns als Beispiel folgendes kleines Programm an, was den Bildschirmspeicher (ab 16384) ins RAM (ab 32768) kopiert :": 1 a$="Sehen Sie auch dazu eine Graphik :": 1 a$="Sehen Sie auch dafuer zwei Beispiele :": 1 a$="Scrollroutine ; scrollt eine Zeile nach oben ; Startadresse = 3280": 1 a$="Schalten Sie jetzt das Tonband ab und lassen Sie es bitte in dieser Bandstellung !": 1 a$="Schalten Sie jetzt bitte das Tonband ein ...": 1 a$="SOUND-Routine : Startadresse = 949": 1 a$="SCREEN$-Routine : Startadressen = 9528 und 11249": 1 a$="S p r u n g b e f e h l e :": 1 a$="R e l a t i v e S p r u e n g e :": 1 a$="R e c h n e n m i t d e m A k k u": 1 a$="R R C und R L C": 1 a$="Programmierung der" 1 a$="Praegen Sie sich vor allen Dingen die Codes von LDIR und LDDR ein, denn sie sind sehr wichtig !": 1 a$="Praegen Sie sich bitte die folgenden Tabellen fest ein. Sie zeigen die logischen Verknuepfungen and, or und xor bezogen auf einzelne Bits :": 1 a$="PRINT-Routine : Startadresse = 16 ( auch mit rst 16 )": 1 a$="PRINT AT 0 , 0 ;": 1 a$="POINT-Routinen : Startadressen 8910 und 7833": 1 a$="PLOT-Routine : Startadresse 8933": 1 a$="OTDR ( Codes 237 , 187 ) macht dagegen das :": 1 a$="Nur wenn der Vergleich zutrifft, wird das Z-Flag auf 1 gesetzt, andernfalls auf 0 .": 1 a$="Nun gehen wir genauso vor, wie im Dezimalsystem : Wir multiplizieren jede Ziffer mit der darueber- stehenden Zahl. Die Summe aller dieser Produkte gibt das Ergebnis (siehe naechste Seite !)." 1 a$="Nun folgt zum Schluss nocheinmal die Erklaerung aller Befehlsarten. Geben Sie dazu einen Befehl ein, und der Computer wird ihn erlaeutern.": 1 a$="Nocheinmal kommen wir zur 237er-Gruppe zurueck, um den Befehl NEG zu erklaeren.": 1 a$="No operation.": 1 a$="Nehmen wir an, wir wollen den ganzen Bildschirm mit dem Buchstaben E auffuellen. Dazu nehmen wir den ASCII-Code vom ""E"" (69), sowie die Anzahl der Buchstaben, die auf den Bildschirm passen (704). " 1 a$="Nehmen wir an, der Inhalt unseres Akkus saehe so aus :": 1 a$="Nebenbei lernen Sie ein neues Flag kennen. Es wird Carry-Flag ( C-Flag ) genannt. Viele Befehle benutzen es, und daher ist es so wichtig. Bei den 8-Bit-Verschiebebefehlen wird es als Zwischenspeicher fuer ein ""herausgerolltes"" Bit verwendet.": 1 a$="Neben den Registerpaaren bc, de, hl und sp gibt es noch die zwei Indexregister ix und iy. Mit ihnen ist es moeglich, eine Art eindimensionale Matrix ( = Array ) abzufragen. Lediglich die Codierung ist hier etwas schwieriger :": 1 a$="Neben den Flags Z und C gibt es noch die Bedingungen Po , Pe , P und M .": 1 a$="Nach dem BASIC-Aufruf PRINT USR 40000 laedt die Z80 das hl-Registerpaar mit 10000 . Danach springt sie zur Routine ab 45000, die das hl-Registerpaar um 2 erhoeht, springt zurueck und uebergibt den Inhalt in das bc-Registerpaar, von dem es mit dem PRINT-Befehl ausgedruckt wird (Ergebnis : 10002 ) .": 1 a$="NEG bedeutet ""negate accumulator"" , d.h., der Akku wird von 256 abgezogen. Das Ergebnis wandert wieder in den Akku. Der Befehl cpl (complement accu), der den Code 47 hat, negiert den Akku, indem er ihn von 255 abzieht. Der Befehl daa (decimal adjust accu) prueft zuerst, ob der Akku > 159 ist. Wenn ja, zieht er 160 ab. Danach wird 6 dazuaddiert. Zu diesen 3 Befehlen nochmal eine Uebersicht :" 1 a$="Multiplikation von zwei Zahlen :": 1 a$="Mit ~ ret ~ springt der Computer zurueck nach BASIC.": 1 a$="Man setzt fuer gewoehnlich eine Warteschleife zwischen die beiden OUT-Befehle. Diese Wartezeit bestimmt die Tonhoehe. Da das ganze aber unbaendig schnell geht, setzen wir den ganzen Vorgang in eine Schleife, die dann die Tonlaenge bestimmt.": 1 a$="Man kann den 254er Port auch zum Erzeugen eines Rauschens benutzen. Dazu schickt man ganz einfach ganz ungeordnete Werte zum Port. Fuer das menschliche Ohr hoert sich das dann wie Rauschen an. Die unterschiedlichen Bytes holen wir uns ganz einfach aus dem ROM.": 1 a$="Man kann dazu die Befehle": 1 a$="Man kann beliebig viele push-Befehle hintereinander ausfuehren, man kommt jedoch mit bis zu zehn ganz gut aus. Vergessen Sie jedoch nie, den Stack so zu verlassen, wie Sie ihn ""betreten"" haben !": 1 a$="Man kann auch mehrere Schleifen ineinander verschachteln. Diese duerfen sich aber, genauso wie in BASIC, nicht ueberlappen. Hier sehen Sie die zwei ineinander verschachtelten Schleifen b und c :": 1 a$="Man kann auch das Port Nr. c mit vielen Befehlen ansprechen. Man benutzt dazu die IN- und OUT-Befehle :": 1 a$="Man kann aber auch stattdessen die beiden Einzelregister b und c benennen. Dabei stellt b das hoeherwertige, und c das niederwertige Byte dar. Das Programm muesste dann lauten :": 1 a$="LD hl , bc": 1 a$="LD hl , 240": 1 a$="LD c , 240": 1 a$="LD bc , hl": 1 a$="LD b , c": 1 a$="LD b , 0": 1 a$="Kanal (0, 1, 2 oder 3) muss vorher im Akku stehen.": 1 a$="Jetzt wird es etwas komplizierter, denn jetzt kommen wir zu dem wichtigsten Element der Z80-Maschinensprache : dem Stack oder besser Stapel.": 1 a$="Jedes dieser Bits hat einen anderen Verwendungszweck. Zuerst wollen wir uns mit dem Zero-Flag beschaeftigen. Dieses Flag ist immer dann eingeschaltet, wenn": 1 a$="Jeder dieser drei Befehle kann jedes der Einzelregister a, b, c, d, e, h, l und (hl) als Operand haben. Wichtig ist, dass sich auch hier wieder alles auf den Akkumulator stuetzt. Also bedeutet die Operation and e --> a and e .": 1 a$="Jeder Zeichencode kommt in den Akku. Mit rst 16 wird er auf den Bildschirm gedruckt. Und so sieht dann ein PRINT AT 0,0; in Maschinencode aus (naechste Seite) :" 1 a$="Ist das Carry-Flag jedoch eingeschaltet, so erhalten Wir als Ergebnis 10 + 5 + 1 = 16.": 1 a$="In einem Programm ist das jedoch nur einmal noetig.": 1 a$="In diese bc-Schleife koennen wir nun unsere Invertierbefehle einsetzten. Dafuer holt der Befehl ld a , ( hl ) sich das laufende Bildschirmbyte in den Akku. Danach invertiert der Befehl cpl den Akku, so dass dann das veraenderte Byte zurueck an seinen Bildschirmplatz kann.": 1 a$="In derselben Art und Weise kann man mit dem Befehl sub vorgehen. Er zieht vom Inhalt des Akkus die entsprechend folgende Variable oder Zahl ab :": 1 a$="Ich gebe Ihnen zu den ROM-Routinen die Startadressen, sowie wichtige Daten an ( Vergessen Sie nicht Ihre Register mit push und pop zu retten ) :": 1 a$="Hier sind auch diese Befehle mit ihren Codes aufgelistet :": 1 a$="Hier bestimmt die b-Schleife die Staerke des Rauschens ( grau bis weiss )": 1 a$="Genauso wie die LDIR / CPIR - Gruppe gibt es auch eine INIR und OTIR - Gruppe (Auf den naechsten Seiten sind sie erklaert.": 1 a$="Genauso wie PEEK und POKE im BASIC Adressen schreiben ( POKE ) , bzw. lesen ( PEEK ) koennen, so kann man sowohl in BASIC, als auch in Maschinensprache mit den Befehlen IN und OUT an den User-Port des Spectrum Signale senden und empfangen.": 1 a$="Geben Sie einen beliebigen Befehl ein (mit Operanden, wie im Anhang C ) !": 1 a$="Folglich endet es erst mit ret z, wenn das b-Register und das c-Register = Null sind.": 1 a$="Ferner gibt es den Befehl bit . Auch ihn steuert man genauso an, wie set und res . Er setzt das Zero-Flag = 1, wenn das betreffende Bit des Rigisters 1 ist, andernfalls = 0 .": 1 a$="Farbe muss vorher im Akkumulator stehen.": 1 a$="Es gibt zwei Arten von Variablenbenutzung: Zum einen die 1-Byte- , und zum Anderen die 2-Byte-Befehle. Die 1-Byte-Variablen lauten a, b, c, d, e, h und l. Die 2-Byte-Variablen sind zwei 1-Byte-Variablen zusammengefasst. Davon gibt es bc, de und hl." 1 a$="Es gibt sogar Befehle, die direkt das Carry-Flag ansprechen : scf und ccf .": 1 a$="Es gibt noch zwei derartige Befehle, die tatsaechlich ein Byte ohne Bitverlust rollen koennen. Sie heissen rrc und rlc (roll right circular und roll left circular).": 1 a$="Es gibt neben den normalen jr-Befehlen einen weiteren, sehr leistungsfaehigen Befehl, der direkt mit dem b-Register zusammenarbeitet. Er wird am haeufigsten fuer Schleifenprogrammierung benutzt :": 1 a$="Es gibt in dieser Art folgende Befehle :": 1 a$="Es gibt aber den Jr - Befehl ( jump relative ). Mit ihm ist es moeglich, relative Sprunge auszufuehren, d.h., man gibt an, um wieviele Stellen weit man springen moechte. Man kann von -126 bis +129 von der momentanen Adresse aus springen." 1 a$="Es gibt aber auch noch ein paar andere Bit-Schiebebefehle. Z.B. rr und rl (roll right und roll left).": 1 a$="Er zieht vom b-Register 1 ab und springt nur dann, wenn b ungleich null ist. djnz bedeutet also nichts anderes als :": 1 a$="Er wird dazu benutzt, die Inhalte von Registerpaaren zwischenzuspeichern, damit sie nicht verlorengehen. Dazu stellen wir uns ein Hauptprogramm vor, welches mit call viele Unterprogramme aufrufen muss. Ihm stehen aber nur 7 Register zur freien Verwendung. Da die Unterprogramme aber selbst Variablen benoetigen, wuerden damit die Register des Hauptprogrammes veraendert werden.": 1 a$="Er tut folgendes :": 1 a$="Er bewirkt": 1 a$="Einige davon koennen wir fuer uns selbst benutzen. Hier sind diese mit ihren Bedeutungen aufgelistet :": 1 a$="Einfuehrung:": 1 a$="Einen ""Klick"" - Ton zum Lautsprecher. Gleichzeitig faerbt sich der Bildschirmrand (BORDER) mit der Farbe des Inhaltes des Akkus.": 1 a$="Eine weitere wichtige Befehlsart in der 203er-Gruppe sind die 8-Bit-Verschiebebefehle. Mit ihnen kann man die 8 Bits eines beliebigen Registers entweder nach links oder nach rechts verschieben.": 1 a$="Eine weitere Moeglichkeit, das Zero-Flag zu veraendern, ist der cp - Befehl (compare). Mit ihm ist es moeglich, den Akku mit einer anderen Variablen oder Zahl zu vergleichen.": 1 a$="Eine weitere Gruppe von Blckbefehlen ist die cp-Gruppe. Auch sie umfasst vier Befehle, mit denen es moeglich ist, ein Byte im Speicher zu suchen.": 1 a$="Eine 2-Byte-Zahl besteht aus einem hoherwertigen und einem niederwertigem Byte. Da sich mit einem Byte aber nur Zahlen von 0 bis 255 darstellen lassen, zaehlt das hoeherwertige Byte in 256er Schritten.": 1 a$="Ein weiterer Punkt, der wichtig fuer den Stack ist, ist das Registerpaar sp. Dieses zeigt automatisch auf die oberste Adresse des Stacks. Da mit dem push-Befehl immer zwei Bytes abgelegt werden, vermindert sich auch das sp-Registerpaar um 2. Veraendern sollten aber nur geuebte Programmierer den Stackpointer ( abgekuerzt sp ), denn wenn er auf eine falsche Art und Weise veraendert wird, kann der Rechner abstuerzen.": 1 a$="Ein ueblicher Befehl, der denn Akku auf Null setzt, ganz egal, was im Akku steht, lautet xor a .": 1 a$="Ein OUT-Befehl in Maschinensprache hat die Form": 1 a$="Ein Beispiel dafuer gibt uns wieder ein Programm :": 1 a$="Ein ""Jump relative""-Befehl erwartet hinter sich nur eine 1-Byte-Zahl. Es gibt natuerlich auch hier alle Verwendungsmoeglichkeiten fuer Flags. Lernen Sie besonders folgende Befehlscodes auswendig :": 1 a$="Druecken Sie jetzt bitte eine Taste ..." 1 a$="Drucken von Strings an der laufenden PRINT-Position : Startadresse = 8252": 1 a$="Dieses Programm ist 8 Bytes lang. Nach dem Aufruf mit PRINT USR 40000 wird es das Ergebnis 180 auf den Bildschirm schreiben." 1 a$="Dieser Code sagt der Z80, dass nun ein Befehl der 203er-Gruppe folgt.": 1 a$="Dieser Befehl verdoppelt also den Inhalt eines Registers. Aber wozu kann man diese beiden Befehle benutzen ?": 1 a$="Dieser Befehl kann immer nur ein ASCII-Zeichen drucken. Fuer PRINT AT muessen wir z.B. den ASCII-Code 22 gefolgt von den Koordinaten als ASCII-Zeichen.": 1 a$="Dieser Befehl hat den Code 16 . Sehen wir uns mal die Benutzung dieses Befehles in einem Programm an :": 1 a$="Dieser Befehl gehoert zur Interruptprogram- mierung !": 1 a$="Diese zwei Codes sagen der Z80 naemlich, dass der naechste Befehl auf ix, bzw. iy bezogen ist.": 1 a$="Diese springen zu den Adressen, die im Befehl stehen. Diese Adressen liegen im ROM-Bereich und dort stehen wichtige Routinen, die das ROM benutzt." 1 a$="Diese 4 Zahlen muessen wir jetzt ab unserer Adresse 40000 bis 40003 ablegen. Das Programm wird mit USR 40000 aufgerufen.": 1 a$="Die zwei Grafiken auf der naechsten Seite veranschaulichen das sehr gut.": 1 a$="Die Zeile muss wieder im c-Register, die Spalte im b-Register stehen. Als Ergebnis zeigt das de-Registerpaar auf die Adresse des Zeichens.": 1 a$="Die Zahlen duerfen nur im Bereich von 0 bis 255 (ein Byte) oder von 0 bis 65535 (zwei Bytes) liegen. Ausserdem hat man nur die Variablen a, b, c, d, e, h und l zur Programmierung zu Verfuegung. Nur das Register a (auch Akkumulator genannt) kann zum Rechnen benutzt werden." 1 a$="Die Y-X-Koordinaten muessen wieder im bc-Register stehen. Das Ergebnis steht dann im c-Register": 1 a$="Die Routinen koennen mit LET l=USR 40000 gestartet werden. Wichtig ist, dass jeder Routine am Ende ein ret-Befehl folgt, um zum BASIC zurueckzuspringen. Vergessen wir das, so kann u.U. der Computer abstuerzen.": 1 a$="Die Funktion XOR (= exclusive or) setzt das Ergebnis-Bit nur dann 1 , wenn das Akku-Bit ungleich dem Register-Bit ist.": 1 a$="Die Eingabe war ungueltig !": 1 a$="Die Codes fuer die Blocktransferbefehle lauten :": 1 a$="Die Codes der Befehle srl , sla , rr und rl :": 1 a$="Die Blocktransferbefehle koennen sehr viele Dinge auf einmal tun, und das auch noch blitzschnell. Man kann hier nichts anderes tun, als aufzulisten, was diese Befehle im Einzelnen tun. Nehmen wir zuerst den Befehl LDI :": 1 a$="Die Befehle der 203er-Gruppe stehen in der Auflistung im Anhang C des Handbuches in der zweiten Spalte. Diese Befehle koennen einzelne Bits von Registerinhalten veraendern oder abfragen.": 1 a$="Die 237er-Gruppe umfasst zwar sehr wenige, dafuer aber sehr leistungsfaehige Befehle. Aber zuerst sehen wir uns die 8 Ld-Befehle mit ihren Codes an :": 1 a$="Des weiteren gibt es den LDIR und den LDDR -Befehl. Der LDIR-Befehl tut das :": 1 a$="Der Vorteil am call-Befehl ist, dass man ein Unterprogramm beliebig oft vom Hauptprogramm aufrufen kann.": 1 a$="Der Speicherbereich des ZX Spectrum 48K:": 1 a$="Der ROM-Bereich (in dem das BASIC-System liegt) liegt im Bereich von 0 bis 16383. Dann folgt der Bildschirmspeicher von 16384 bis 22527, dann die Farben des Bildschirms von 22528 bis 23297." 1 a$="Der Mikroprozessor kann allerdings immer nur mit einem Registersatz arbeiten. Zum Austauschen der Registersaetze benutzt man den Befehl EXX 1 a$="Der Ladebefehl : Der Befehl ld (sprich load) entspricht dem LET-Befehl im BASIC. Um z.B. der Variablen b den Wert von c zuzuweisen, schreiben Sie :": 1 a$="Der Jump-Befehl veranlasst stattdessen die Z80 dazu, einfach an der festgelegten Stelle weiterzumachen . Das Programm": 1 a$="Der Gegenbefehl dazu sieht logischerweise so aus :": 1 a$="Der Code des Befehles call NN lautet 205 , der Code von JP NN lautet 195 . Sehen wir uns folgendes Beispiel an :": 1 a$="Der Befehl ~nop~ ": 1 a$="Der Befehl cpi tut folgendes :": 1 a$="Der Befehl OTIR ( Codes 237 , 179 ) macht folgendes :": 1 a$="Der Befehl "+d$+" tut die oben beschriebenen Dinge.": 1 a$="Der Befehl sla tut genau dasselbe wie srl, nur in der anderen Richtung. Er verschiebt das angegebene Register um ein Bit nach links, wobei diesmal das linkeste Bit ins Carry-Flag wandert. Auf der rechten Seite rutscht eine Null hinein.": 1 a$="Der Befehl ld ( hl ) , a entspricht dem BASIC-Befehl POKE hl , a .": 1 a$="Der Befehl OUTI (Codes 237 , 163) macht das :": 1 a$="Der Befehl OUTD (Codes 237 , 171) macht das :": 1 a$="Der Befehl LDD hingegen tut das :": 1 a$="Der Befehl INI ( Codes 237 , 162 ) tut Folgendes auf einmal :": 1 a$="Der Befehl INDR (Codes 237 , 186) tut folgendes aufeinmal :": 1 a$="Der Befehl IND (Codes 237 , 170) tut dagegen das :": 1 a$="Der Befehl "+i$: 1 a$="Der Befehl ex de , hl , der den Code 235 hat, tauscht die Inhalte der Register de und hl untereinander aus.": 1 a$="Der Akku sieht dann so aus :": 1 a$="Der sbc-Befehl geht genauso vor; er zieht vom Akku zusaetzlich noch das Carry-Flag ab.": 1 a$="Der INIR - Befehl (Codes 237 , 178) macht das :": 1 a$="Den letzten Bit-Schibebefehl, den Sie wissen muessen, heisst sra . Er verschiebt die Bits nach rechts und auch hier wandert das rechteste Bit ins Carry-Flag. Das linkeste Bit (Bit 7) wird allerdings nach dem Verschieben selbst nocheinmal in die Luecke gesetzt. Die Grafik zeigt es naeher :": 1 a$="Den Uebertrag koennen Sie sich genauso wie im Dezimalsystem in der Rechnung vermerken. Sehen Sie dazu folgendes Beispiel. Die Binaerzahlen 101011 und 100110 sollen addiert werden :": 1 a$="Demnach macht der LDDR-Befehl das :": 1 a$="Dazu benutzen wir den Anhang C des BASIC-Handbuches. Wir suchen zuerst nach dem Befehl LD a , b und finden ihn unter dem Code 120 ; dann finden wir LD h , d unter 98 ; LD d , c unter 81 und ret unter 201.": 1 a$="Das waeren also die wichtigsten Befehle der Z80. Ab der naechsten Seite finden Sie die wichtigsten ROM-Routinen fuer den Spectrum . . .": 1 a$="Das waeren also die beruechtigten Schiebebefehle der 203er-Gruppe. Damit waere die 203er-Gruppe abgeschlossen, so dass wir uns jetzt den Befehlen der 237er-Gruppe widmen koennen.": 1 a$="Das liegt daran, dass hier der Akku mit sich selbst verknuepft wird und durch xor alle Bits des Ergebnisses auf Null gesetzt werden. and a und or a veraendern den Akku nicht.": 1 a$="Das kann man also auf alle hl-bezogenen Befehle in dieser Art anwenden, bis auf die Befehle, in denen hl in Klammern steht.": 1 a$="Das ist der zweite Teil unseres Maschinensprache-Kurs. Wir hatten uns zuletzt mit den Bit-veraenderungs- und -Abfragebefehlen set , res und bit beschaeftigt.": 1 a$="Das hl-Registerpaar, das hier in Klammern steht, bedeutet ""der Inhalt der Adresse hl "". Also entspricht der Ausdruck ld a , ( hl ) dem BASIC-Befehl LET a=PEEK hl . Auch hier ist das Ergebnis eine Zahl zwischen 0 und 255.": 1 a$="Das fertige Programm sieht dann so aus :": 1 a$="Das bedeutet, dass nach dem Befehl LD bc , NN noch zwei weitere Zahlen folgen muessen, damit der Befehl vollstaendig wird. Um das zu verstehen, muessen wir uns mit 2-Byte-Zahlen vertraut machen.": 1 a$="Das bedeutet, dass man den Inhalt des Akkus an die Port-Adresse N schickt. Wir aber wollen uns nur mit dem Port Nr. 254 beschaeftigen, denn dieser wird fuer die Ansprechung auf den Lautsprecher benutzt. Z.B. schickt der Befehl": 1 a$="Das bedeutet, dass jeder Befehl, der ein ( hl ) innehat, noch eine weitere Zahl erwartet. Das ist eine 1-Byte-Zahl zwischen 0 und 255. Also laedt der Akku mit diesem Befehl das Byte, das an Adresse ( ix + N ) steht." 1 a$="Das bedeutet, das nach dem Aufruf eines Programmes mit LET re=USR 40000 der BASIC-Variablen re der Wert des bc-Registerpaares zugewiesen wird. Um das zu beweisen, sehen wir uns folgendes Programm an :": 1 a$="Das allerwichtigste bei dem Umgang mit push und pop ist, dass das zuletzt auf dem Stack abgelegte Element auch zuerst wieder vom Stack geholt werden muss. Das saehe in einem programm dann so aus :": 1 a$="Das Zero-Flag ist besonders nuetzlich, um Schleifen zu programmieren. Nehmen wir an, wir wollen von der Zahl 100 bis 0 rueckwaerts zaehlen, so koennen wir wie folgt vorgehen :": 1 a$="Das Programm kehrt bereits nach BASIC zurueck, wenn a den Wert 100 erreicht hat. Der zweite ret-Befehl wird hier also nicht erreicht.": 1 a$="Das Ergebnis-Bit wird bei der Funktion AND also nur dann 1 , wenn das Akku-Bit und": 1 a$="Das Ergebnis lautet hier logischerweise 100.": 1 a$="Das Carry-Flag und der Akkumulator": 1 a$="Das BASIC-Programm beginnt ab Adresse 23755. Der Beginn aller nachfolgenden Bereiche (Variablen, usw.) ist von der Laenge des BASIC-Programmes abhaengig. Das bedeutet, dass, wenn Sie auch nur eine Programmzeile eingeben, sich der ganze nachfolgende Bereich um die Laenge dieser Zeile verschiebt." 1 a$="Das af- Registerpaar ( Akku & Flags ) kann man extra nocheinmal mit dem Befehl EX af , af' ( Code 8 ) austauschen.": 1 a$="Daraus ergibt sich fuer das Bytepaar : 245 + 8704 = 8949": 1 a$="Damit wollen wir erst einmal die 237er-Gruppe verlassen und zum normalen Befehlssatz zurueckkehren. Wir werden jetzt etwas ueber die logischen Operationen AND OR und XOR erfahren. Glauben Sie bloss nicht, dass es so einfach wie in BASIC ist.": 1 a$="Dafuer gibt es folgende Befehle mit ihren Codes :" 1 a$="Dabei werden alle hl-Register in dem Befehl zu ix, bzw. iy umgewandelt. Als Beispiel nehmen wir ld hl , 1000 . Wenn wir nun den Code 221 vor diesen Befehl setzen, verwandelt er sich in ld ix , 1000.": 1 a$="Da sich die c - Schleife innerhalb der b - Schleife befindet, wird die c-Schleife 100 mal durchlaufen, also solange, bis beide Register gleich Null sind.": 1 a$="Da das hoeherwertige Byte aber immer in 256er Schritten zaehlt, muessen wir das Byte noch mit 256 malnehmen.": 1 a$="D i e B e f e h l e I N u n d OUT" 1 a$="D i e R e s t a r t - B e f e h l e :": 1 a$="D i e I n d e x r e g i s t e r": 1 a$="D i e 2 3 7 e r - G r u p p e": 1 a$="D i e 2 0 3 e r - G r u p p e :": 1 a$="D e r S t a c k ( S t a p e l ) :": 1 a$="D a s b i n a e r e Z a h l e n s y s t e m :": 1 a$="Codes": 1 a$="Codes :": 1 a$="Code": 1 a$="CLS - Routine : Startadresse = 3435": 1 a$="Bitte beachten Sie hier, dass Sie genauso vorgehen, wie im Dezimalsystem. D.h., dass beim Addieren von 3 Einsen, unten eine 1 hingeschrieben und eine weitere 1 in die naechste Stelle uebertragen werden muss, da ": 1 a$="Bisher kennen Sie die einfachsten Befehle der Z-80 : ld , add , sub , inc und sub . Hier ist eine Liste mit den wichtigsten Befehlen, die Sie unbedingt auswendig wissen muessen, mit ihren Codes zusammengestellt :": 1 a$="Bildkanal oeffnen : Startadresse = 5633": 1 a$="Bevor man zum ersten Male etwas druckt, sollte man dem Computer sagen, in welchen Bildschirmberiech er drucken soll. Im BASIC druckt er immer im Bereich # 2 . Fuer den unteren Bereich gibt man dann entweder # 0 oder # 1 an.": 1 a$="Beim Subtrahieren gehen Sie genauso vor. Merken Sie sich dafuer bitte folgende Binaerzahlen :": 1 a$="Bei der Funktion OR dagegen wird das Ergeb- nis-Bit 1 , wenn das Akku-Bit oder": 1 a$="Bei den Befehlen ld a , ( NN ) und ld ( NN ) , a wird die 2-Byte-Adresse nach dem Befehlscode angefuegt.": 1 a$="Befehle :": 1 a$="Beachten Sie,dass alle diese Codes in der 203er Gruppe stehen und deshalb die Zahl 203 vorangestellt werden muss.": 1 a$="Beachten Sie, dass den Befehlen LD b , N und LD c , N hier nur eine 1-Byte-Zahl folgt.": 1 a$="BORDER-Routine : Startadresse = 8859": 1 a$="B l o c k t r a n s f e r b e f e h l e": 1 a$="Auf diese Art koennen maximal 7 Schleifen aufgebaut werden ; es stehen ja auch nur 7 Register dafuer zur Verfuegung.": 1 a$="Auch hier gibt es natuerlich automatische Blockbefehle, sie heissen cpir und cpdr . Sie tun auch hier dasselbe wie cpi und cpd, nur, dass sie das solange tun, bis entweder der Akku gleich dem Byte ( hl ) ist, oder bc=0 ist.": 1 a$="Auch diese vier Bytes koennen Sie von Adresse 40000 bis 40003 einpoken." 1 a$="Auch diese beiden Befehle verschieben in gleicher Weise ein beliebiges Register, nur gibt es keine Luecken , denn auf der einen Seite rutscht das Carry-Flag hinein, waehrend auf der anderen Seite das ""herausgerollte"" Bit wieder ins Carry-Flag rutscht.": 1 a$="Auch diese Befehle sprechen das Port mit der Nummer ( c ) an.": 1 a$="Auch dazu wieder ein Beispiel :": 1 a$="Anschliessend muessen wir das Ergebnis wieder ins bc Registerpaar laden, damit wir es uns in BASIC ansehen koennen. Das Programm sieht wie folgt aus :": 1 a$="Am nuetzlichsten davon ist rst 16 fuer uns. Denn damit ist es moeglich, genauso, wie im BASIC mit PRINT zu arbeiten.": 1 a$="Also koennen wir schreiben :": 1 a$="Also erhalten wir fuer den Befehl LD bc , 240 die Byte-Folge 1 , 240 , 0 (wobei das niederwertige Byte zuerst geschrieben wird). Die Bytes fuer unser vorhin geschriebenes Programm lauten demnach:": 1 a$="Aber wie rechnet man sich die 1-Byte-Zahl DIS aus, um zur Zieladresse zu springen ?": 1 a$="Aber wie koennen wir dieses Programm in den Computer hineinbekommen ?": 1 a$="Aber man wuerde in BASIC nichts mit dieser Routine anfangen koennen, da BASIC andere Variablen als die Maschinensprache benutzt. Das einzige Register, das vom BASIC benutzt werden kann ist bc ." 1 a$="Aber es gibt fuer jeden Bedingungsbefehl auch eine Gegenfunktion, in der einfach vor das Flag ein n fuer ""not"" davorgestellt wird . Also springt der Befehl": 1 a$="Aber dazu spaeter. Sehen wir uns zuerst einmal an, wie ein Register vorher und hinterher aussieht.": 1 a$="Aber auch zum Rollen des Bildschirminhaltes lassen sich diese beiden Befehle gut nutzen, wie Sie spaeter sehen werden.": 1 a$="ATTR-Routine : Startadressen = 9603 und 7833": 1 a$="ASCII- oder Farbzeichen-Code muss vor dem Aufruf im Akku stehen.": 1 a$="= 1386": 1 a$="6 , 0": 1 a$="33 , 240 , 0": 1 a$="3) Die Bedingung P trifft zu, wenn die zuletzt ausgefuehrte Operation zu einer positive Zahl fuehrte, die Bedingung M hingegen, wenn die Zahl negativ war.": 1 a$="253 prefixes instructions using iy": 1 a$="221 prefixes instructions using ix": 1 a$="2) Die Bedingung Pe bedeutet ""parity even"" (gerade) und trifft zu, wenn die zuletzt ausgefuehrte Operation eine gerade Zahl lieferte,": 1 a$="2 4 5": 1 a$="2 4 5 +": 1 a$="14 , 240": 1 a$="1) Die Bedingung Po bedeutet ""parity odd"" (ungerade) und trifft zu, wenn die zuletzt ausgefuehrte Operation eine ungerade Zahl lieferte.": 1 a$="1 3 8 6 =": 1 a$="1 , 240 , 0": 1 a$="1 + 1 = 0": 1 a$="1 + 1 + 1 = 11 ist.": 1 a$="1 + 0 = 1": 1 a$="0 + 1 = 1": 1 a$="0 + 0 = 0": 1 a$="* 2 5 6": 1 a$="( Bei laengeren Texten rate ich jedoch zur Verwendung einer Schleife )": 1 a$="( Alle fuer ix beschriebenen Dinge treffen natuerlich auch auf iy zu ).": 1 a$=" 3 4": 1 Z80-Kurs 3 1 Z80-Kurs 2zv 1 Z80-Kurs 1 1 Punkt 1) springen, bis bc = 0" 1 Druecken Sie jetzt bitte eine Taste ... 1 ;"________ = Uebertraege"; 1 ;"101011 (43)"; 1 ;"1010001 (81)" 1 ;"+ 100110 (38)"; 1 ;" Bitte eine Taste druecken ... ": 1 ;" Die wichtigsten 1 1 + 1 = 0" 1 1 + 0 = 0"," 1 0 + 1 = 0"," 1 ,"sub N",214 1 ,"ld l , N",46 1 ,"ld hl,NN",33 1 ,"ld h , N",38 1 ,"ld e , N",30 1 ,"ld de,NN",17 1 ,"ld d , N",22 1 ,"ld c , N",14 1 ,"ld b , N",6 1 ,"ld a , N",62 1 ,"inc l",44 1 ,"inc hl",33 1 ,"inc h",36 1 ,"inc e",28 1 ,"inc de",19 1 ,"inc d",20 1 ,"inc c",12 1 ,"inc bc",3 1 ,"inc b",4 1 ,"inc a",60 1 ,"dec l",45 1 ,"dec hl",43 1 ,"dec h",37 1 ,"dec e",29 1 ,"dec de",27 1 ,"dec d",21 1 ,"dec c",13 1 ,"dec bc",11 1 ,"dec b",5 1 ,"dec a",61 1 ,"b","c","d","e","h","l","( hl )","a","sla ",32 1 ,"b","c","d","e","h","l","( hl )","a","rr ",24 1 ,"b","c","d","e","h","l","( hl )","a","rl ",16 1 ,"b","c","d","e","h","l","( hl )","a" 1 ,"add a , N",198 1 ,"LD h , d",81 1 ,"LD d , c",201 1 ,"LD a , b",98 1 )+" . Das Ergebnis wandert ins Register "+p$+" .": 1 (q$="(ix+N)" 1 (p$="(ix+N)" 1 ( Code 217 ).": 1 "sbc hl , bc","237 , 66","adc hl , bc","237 , 74","sbc hl , de","237 , 82","adc hl , de","237 , 90","sbc hl , hl","237 , 98","adc hl , hl","237 , 106","sbc hl , sp","237 , 114","adc hl , sp","237 , 122" 1 "rst 0","entspricht NEW in BASIC","rst 16","entspricht PRINT in BASIC","rst 24","liest das naechte zu interpretierende"," 1 "ret x ","jp x , NN","call x , NN" 1 "push bc"," 1 "ldi","237 , 160","ldd","237 , 168","ldir","237 , 176","lddr","237 , 184": 1 "ld bc,NN",1 1 "ld bc , 2048","ld a , 255","ld de , 65535","push af","push de","push bc","call 5633","pop bc","pop de","pop af","ret" 1 "ld ( de ) , a"," 1 "ld ( NN ) , bc","237 , 67","ld bc , ( NN )","237 , 75","ld ( NN ) , de","237 , 83","ld de , ( NN )","237 , 91","ld ( NN ) , hl","237 , 99","ld hl , ( NN )","237 , 107","ld ( NN ) , sp","237 , 115","ld sp , ( NN )","237 , 123" 1 "jr c , DIS","jr nc , DIS","jp c , NN","jp nc , NN","call c , NN","call nc , NN","ret c","ret nc" 1 "cp ( hl )","hl = hl - 1","bc = bc - 1","zurueck, bis entweder bc=0","oder a=( hl )": 1 "cp ( hl )","hl = hl - 1","bc = bc - 1"," 1 "cp ( hl )","hl = hl + 1","bc = bc - 1","zurueck, bis entweder bc=0","oder a=( hl )": 1 "cp ( hl )","hl = hl + 1","bc = bc - 1"," 1 "Port c --> ( hl )","hl = hl + 1","b = b - 1"," 1 "Port c --> ( hl )","hl = hl - 1","b = b - 1"," 1 "Port c ---> ( hl )","hl = hl - 1","b = b - 1","zurueck, bis b=0"," 1 "Port c ---> ( hl )","hl = hl + 1","b = b - 1","zurueck, bis b=0"," 1 "LD a , 180","62 , 180","LD d , 80","22 , 80","sub d","146","LD b , 0","6 , 0","LD c , a","79","ret","201" 1 "LD a , 100","62 , 100","add a , 80","198 , 80","LD b , 0","6 , 0","LD c , a","79","ret","201" 1 "Befehl","Codes","Aufgabe","neg","237 , 68","a = 256 - a","cpl","47","a = 255 - a","daa","39","1) wenn a > 160 , a = a - 160"," 1 "Adresse","Befehle","Codes","x","40000","ld hl , 16384","33 , 0 , 64","40003","ld bc , 6144","1 , 0 , 24","40006","ld a , ( hl )","126","40007","cpl","47","40008","ld ( hl ) , a","119","40009","dec bc","11","40010","ld a , b","120" 1 "Adresse","Befehle","Codes","x","40000","ld hl , 10000","33 , 16 , 39","40003","call 45000","205 , 200 , 175","40006","ld b , h","68","40007","ld c , l","77","40008","ret","201","x","45000","inc hl","35","45001","inc hl","35","45002","ret","201" 1 "Adresse","Befehle","Codes","x","40000","ld hl , 1000","33 , 232 , 3","40003","ld a , 0","62 , 0","40005","out ( 254 ) , a","211 , 254","40007","ld b , 200","6 , 200","40009","djnz, <---<","16 , 254" 1 "Adresse","Befehle","Codes","x","40000","ld hl , 0","33 , 0 , 0","40003","inc hl","35","40004","inc hl","35","40005","jp 40003","195 , 67 , 156","40008","ret","201" 1 "Adresse","Befehle","Codes","x","40000","ld a , 0","62 , 0","40002","ld b , 200","6 , 200","40004","inc a","60","40005","cp 100","254 , 100","40007","ret z","200","40008","djnz 250","16 , 250","40010","ret","201" 1 "Adresse","Befehle","Codes","x","40000","ld a , 0","62 , 0","40002","ld b , 150","6 , 150","40004","inc a","60","40005","djnz 253","16 , 253","40007","ret","201" 1 "Adresse","Befehle","Codes","x","40000","ld a , 0","62 , 0","40002","ld b , 12","6 , 12","40004","add a , 14","198 , 14","40006","djnz 252","16 , 252","40008","ret","201" 1 "40022","or c","177","40023","jr nz , ","32 , 246","40025","ret","201" 1 "40011","or c","177","40012","ret z","200","40013","inc hl","35","40014","jr","24 , 246" 1 "40011","ld a , 255","62 , 255","40013","out ( 254 ) , a","211 , 254","40015","dec hl","43","40016","ld a , h","124","40017","or l","181","40018","jr nz,","32 , 239","40020","ret","201" 1 "40008","xor a","175","40009","rst 16","215","40010","xor a","175","40011","rst 16","215","40012","ld bc , 704","1 , 192 , 2","40015","ld a , 69","62 , 69","40017","push bc","197","40018","rst 16","215","40019","pop bc","193","40020","dec bc","11","40021","ld a , b","120" 1 "40008","dec b","b=b-1","40009","jp nz , 40002","wenn b < > 0, Jp","40012","ret"," 1 "40006","ret","ist, Sprung" 1 "40000","ld hl , 2560","33 , 0 , 10","40003","ld a , ( hl )","126","40004","out ( 254 ) , a","211 , 254","40006","ld b , 40","6 , 40","40008","djnz <---<","16 , 254","40010","dec hl","43","40011","ld a , h","124","40012","or l","181","40013","jr nz ,","32 , 244","40014","ret","201" 1 "40000","ld hl , 16384","33 , 0 , 64","40003","ld de , 32768","17 , 0 , 64","40006","ld bc , 6912","1 , 0 , 27","40009","ldir","237 , 176","40011","ret","201": 1 "40000","ld b , 100","b-Schleife","40002","ld c , 50","c-Schleife","40004","dec c","c=c-1","40005","jp nz , 40004","wenn c < > 0, Jp" 1 "40000","ld a , 22","62 , 22","40002","rst 16","215","40003","ld a , 0","62 , 0","40005","rst 16","215","40006","ld a , 0","62 , 0","40008","rst 16","215" 1 "40000","ld a , 2","62 , 2","40002","call 5633","205 , 1 , 22","40005","ld a , 22","62 , 22","40007","rst 16","215" 1 "40000","ld a , 100","100=Startwert","40002","dec a","a=a-1","40003","jp nz , 40002","solange a < > 0" 1 "40000","jr","40001","DIS","40002","inc a","40003","dec a","40004","ret" 1 "39997","inc a","39998","dec a","39999","ret","40000","jr","40001","DIS" 1 "10","11","100","101","110","111","1000": 1 "1) den Inhalt vom Port c zum Byte ( hl )"," 1 "1) Port c zum Byte ( hl )","2) b = b - 1","3) hl = hl + 1","4) zu Pkt. 1) springen, bis b = 0": 1 "1) Byte ( hl ) zum Port c bringen","2) b = b - 1","3) hl = hl - 1": 1 "1) Byte ( hl ) zum Port c bringen","2) b = b - 1","3) hl = hl + 1": 1 "1) Byte ( hl ) zum Port c bringen","2) b = b - 1","3) hl = hl - 1","4) zum Pkt. 1) springen, bis b = 0": 1 "1) Byte ( hl ) zum Port c bringen","2) b = b + 1","3) hl = hl + 1","4) zum Punkt 1) springen, bis b = 0" 1 ",a$,"ret z"," 1 ",a$,"or c"," 1 ",a$,"ld bc , 6144"," 1 ",a$,"ld a , b"," 1 ",a$,"dec bc"," 1 ",a$,"2) a = a + 6" 1 ",a$,". . . . . . ."," 1 ","pop hl","push af"," 1 ","pop de","push hl"," 1 ","pop bc","push de"," 1 ","pop af" 1 ","ld hl , 16384"," 1 ","Zeichen im BASIC-Programm" 1 ","Code","x","ld a , ( bc )"," 1 ","Code","x","add hl , bc"," 1 ","9","add hl , de"," 1 ","58","ld ( bc ) , a"," 1 ","26","ld a , ( hl )"," 1 ","25","add hl , hl"," 1 ","18","ld ( hl ) , a"," 1 ","126","ld a , ( NN )"," 1 ","119","ld ( NN ) , a"," 1 ","10","ld a , ( de )"," 1 "( hl ) --> Port c","hl = hl - 1","b = b - 1"," 1 "( hl ) --> Port c","hl = hl + 1","b = b - 1"," 1 "( hl ) --> ( de )","de = de - 1","hl = hl - 1","bc = bc - 1","zurueck, bis bc = 0": 1 "( hl ) --> ( de )","de = de + 1","hl = hl + 1","bc = bc - 1","zurueck, bis bc = 0": 1 "( hl ) ---> Port c","hl = hl - 1","b = b - 1","zurueck, bis b=0"," 1 "( hl ) ---> Port c","hl = hl + 1","b = b - 1","zurueck, bis b=0"," 1 "( hl ) ---> ( de )","de = de + 1","hl = hl + 1","bc = bc - 1"," 1 "( de ) --> ( hl )","de = de - 1","hl = hl - 1","bc = bc - 1"," 1 zur Adresse de bringen","2) de = de + 1","3) hl = hl + 1","4) bc = bc - 1" 1 fuer den ZX-Spectrum"